// lc32View.cpp : implementation of the CLc32View class
//

#include "stdafx.h"
#include "lc32.h"

#include "lc32Doc.h"
#include "lc32View.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CLc32View

IMPLEMENT_DYNCREATE(CLc32View, CFormView)

BEGIN_MESSAGE_MAP(CLc32View, CFormView)
	//{{AFX_MSG_MAP(CLc32View)
	ON_BN_CLICKED(IDC_BTNSTART, OnMCStart)
	ON_BN_CLICKED(IDC_BTNSTOP, OnMCStop)
	ON_WM_HSCROLL()
	ON_UPDATE_COMMAND_UI(ID_PAINT_VIEW, OnUpdatePaintView)
	//}}AFX_MSG_MAP
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, CFormView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CFormView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CFormView::OnFilePrintPreview)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CLc32View construction/destruction

CLc32View::CLc32View()
	: CFormView(CLc32View::IDD)
{
	//{{AFX_DATA_INIT(CLc32View)
	m_fElField = 1.0f;
	m_fAnchCoeff = 18.0f;
	m_iMCStep = 0;
	m_iTimeout = 1;
	m_fAnchProb = 1.0f;
	//}}AFX_DATA_INIT
	// TODO: add construction code here
}

CLc32View::~CLc32View()
{
}

void CLc32View::DoDataExchange(CDataExchange* pDX)
{
	CFormView::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CLc32View)
	DDX_Control(pDX, IDC_TIMEOUT, m_ctrlTimeout);
	DDX_Control(pDX, IDC_BTNSTOP, m_btnStop);
	DDX_Control(pDX, IDC_BTNSTART, m_btnStart);
	DDX_Text(pDX, IDC_EFIELD, m_fElField);
	DDV_MinMaxFloat(pDX, m_fElField, 0.f, 4.f);
	DDX_Text(pDX, IDC_ACOEFF, m_fAnchCoeff);
	DDV_MinMaxFloat(pDX, m_fAnchCoeff, 0.f, 20.f);
	DDX_Text(pDX, IDC_MCSTEP, m_iMCStep);
	DDX_Text(pDX, IDC_TMOUT, m_iTimeout);
	DDX_Text(pDX, IDC_APROB, m_fAnchProb);
	DDV_MinMaxFloat(pDX, m_fAnchProb, 0.f, 1.f);
	//}}AFX_DATA_MAP
}

BOOL CLc32View::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CFormView::PreCreateWindow(cs);
}

void CLc32View::OnInitialUpdate()
{
	CFormView::OnInitialUpdate();
	ResizeParentToFit();

	m_ctrlTimeout.SetRange(0, 20);
	m_ctrlTimeout.SetTicFreq(1);
}

/////////////////////////////////////////////////////////////////////////////
// CLc32View printing

BOOL CLc32View::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

void CLc32View::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add extra initialization before printing
}

void CLc32View::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add cleanup after printing
}

void CLc32View::OnPrint(CDC* pDC, CPrintInfo* /*pInfo*/)
{
	// TODO: add customized printing code here
}

/////////////////////////////////////////////////////////////////////////////
// CLc32View diagnostics

#ifdef _DEBUG
void CLc32View::AssertValid() const
{
	CFormView::AssertValid();
}

void CLc32View::Dump(CDumpContext& dc) const
{
	CFormView::Dump(dc);
}

CLc32Doc* CLc32View::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CLc32Doc)));
	return (CLc32Doc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CLc32View message handlers

UINT CLc32View::MyThreadProc(LPVOID pParam)
{
	CLc32View *pView = (CLc32View*)pParam;

	if (pView == NULL || !pView->IsKindOf(RUNTIME_CLASS(CLc32View)))
		return -1;

	CSingleLock threadLock(&pView->m_mutex);
	CLc32Doc *pDoc = pView->GetDocument();
	int iStepTimeout = 1;

	pDoc->CreateLiquidCrystal(20, 20);
	pDoc->SetAllMoleculesAngle(-15);
	pDoc->SetSurfaceAnchoring(1.0f - pView->m_fAnchProb);
	pDoc->SetSystemProperties(pView->m_fElField, pView->m_fAnchCoeff);
	pView->m_iMCStep = 0;

	TRACE3("MC symulation started. E=%.2f,A=%.2f,P=%.2f\n", pView->m_fElField, pView->m_fAnchCoeff, 1.0f - pView->m_fAnchProb);

	while (1)
	{
		threadLock.Lock();
		if (threadLock.IsLocked())
		{
			if (pView->m_bStopThread)
			{
				threadLock.Unlock();
				break;
			}
#ifdef _DEBUG
			if (iStepTimeout != pView->m_iTimeout)
			{
				TRACE1("Timeout: %dms\n", pView->m_iTimeout);
			}
#endif
			iStepTimeout = pView->m_iTimeout;
			threadLock.Unlock();
		}

		pDoc->MakeMCSteps(1);
		Sleep(iStepTimeout);
	}
	pDoc->DestroyLiquidCrystal();

	TRACE0("MC symulation stopped\n");

	return 0;
}

void CLc32View::OnMCStart() 
{
	UpdateData();
	m_bStopThread = false;
	m_pThread = AfxBeginThread(MyThreadProc, this);
	m_pThread->m_bAutoDelete = false;
}

void CLc32View::OnMCStop() 
{
	CSingleLock threadLock(&m_mutex);

	threadLock.Lock();
	if (threadLock.IsLocked())
	{
		m_bStopThread = true;
		threadLock.Unlock();

		WaitForSingleObject(m_pThread->m_hThread, INFINITE);
		delete m_pThread;
	}
}

void CLc32View::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{	
	CFormView::OnHScroll(nSBCode, nPos, pScrollBar);

	if (pScrollBar->IsKindOf(RUNTIME_CLASS(CSliderCtrl)))
	{
		CSingleLock threadLock(&m_mutex);

		threadLock.Lock();
		if (threadLock.IsLocked())
		{
			m_iTimeout = max(1, 5*m_ctrlTimeout.GetPos());
			threadLock.Unlock();
		}
		UpdateData(FALSE);
	}
}

void CLc32View::OnUpdatePaintView(CCmdUI* pCmdUI) 
{
	CSingleLock threadLock(&m_mutex);

	threadLock.Lock();
	if (threadLock.IsLocked())
		pCmdUI->Enable(!m_bStopThread);
	else
		pCmdUI->Enable(FALSE);
}
